package com.pb.camera.work;

import android.os.Handler;
import android.os.Message;

import com.pb.camera.utils.Logger;
import com.pb.camera.utils.TaskHelper;
import com.pb.camera.utils.TaskHelper.Task;
import com.tutk.IOTC.AVAPIs;
import com.tutk.IOTC.AVIOCTRLDEFs;
import com.tutk.IOTC.CommApis;
import com.tutk.IOTC.Packet;
import com.umeng.common.message.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Observable;

/*
    Camera 持有一个 RecviceTask
          被观察者，其内部属性如果有变化可以实时通知观察者。实现和具体功能类的分离
 */
public class ReceiveTask extends Observable {
    private static final int MAX_BUF_SIZE = 1024;
    private final String TAG = "ReceiveTask";
    private AVIOCTRLDEFs mAVIOCTRLDEFs;
    private static ReceiveTask mDefault = new ReceiveTask();

    public static ReceiveTask getDefault() {
        return mDefault;
    }

    private boolean mGetListWifiDone;
    private boolean isStart;

    private ReceiveTask() {
        mAVIOCTRLDEFs = new AVIOCTRLDEFs();
    }

    public AVIOCTRLDEFs.SMsgAVIoctrlGetStreamCtrlResp mStreamCtrlResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetStreamCtrlResp mSMsgAVIoctrlSetStreamCtrlResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetMotionDetectResp mSMsgAVIoctrlSetMotionDetectResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetMotionDetectResp mSMsgAVIoctrlGetMotionDetectResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlDeviceInfoResp mSMsgAVIoctrlDeviceInfoResp;
    //public AVIOCTRLDEFs.SMsgAVIoctrlSetPasswdResp mSMsgAVIoctrlSetPasswdResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlListWifiApResp mSMsgAVIoctrlListWifiApResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetWifiResp mSMsgAVIoctrlSetWifiResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetWifiResp mSMsgAVIoctrlGetWifiResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetRecordResp mSMsgAVIoctrlSetRecordResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetRecordResp mSMsgAVIoctrlGetRecordResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetRcdDurationResp mSMsgAVIoctrlSetRcdDurationResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetRcdDurationResp mSMsgAVIoctrlGetRcdDurationResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlListEventResp mSMsgAVIoctrlListEventResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetVideoModeResp mSMsgAVIoctrlSetVideoModeResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetVideoModeResp mSMsgAVIoctrlGetVideoModeResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlSetEnvironmentResp mSMsgAVIoctrlSetEnvironmentResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetEnvironmentResp mSMsgAVIoctrlGetEnvironmentResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetStreamCtrlResp mSMsgAVIoctrlGetStreamCtrlResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlFormatExtStorageResp mSMsgAVIoctrlFormatExtStorageResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetSupportStreamResp mSMsgAVIoctrlGetSupportStreamResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetAudioOutFormatResp mSMsgAVIoctrlGetAudioOutFormatResp;
    public AVIOCTRLDEFs.SMsgAVIoctrlGetFlowInfoResp mSMsgAVIoctrlGetFlowInfoResp;

    private Handler mMainHanler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_DEVINFO_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (null == mSMsgAVIoctrlDeviceInfoResp)
                        mSMsgAVIoctrlDeviceInfoResp = mAVIOCTRLDEFs.new SMsgAVIoctrlDeviceInfoResp();
                    AVIOCTRLDEFs.SMsgAVIoctrlDeviceInfoResp resp = mAVIOCTRLDEFs.new SMsgAVIoctrlDeviceInfoResp();
                    mSMsgAVIoctrlDeviceInfoResp.model = Arrays.copyOfRange(bytes, 0, 16);
                    mSMsgAVIoctrlDeviceInfoResp.vendor = Arrays.copyOfRange(bytes, 16, 32);
                    mSMsgAVIoctrlDeviceInfoResp.version = bytes[35] + "." + bytes[34] + "." + bytes[33] + "." + bytes[32];
                    mSMsgAVIoctrlDeviceInfoResp.channel = Packet.byteArrayToInt_Little(bytes, 36);
                    mSMsgAVIoctrlDeviceInfoResp.total = Packet.byteArrayToInt_Little(bytes, 40);
                    mSMsgAVIoctrlDeviceInfoResp.free = Packet.byteArrayToInt_Little(bytes, 44);
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlDeviceInfoResp);
                    Logger.d(TAG, "ver:" + resp.version);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_GET_VIDEOMODE_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlGetVideoModeResp == null)
                        mSMsgAVIoctrlGetVideoModeResp = mAVIOCTRLDEFs.new SMsgAVIoctrlGetVideoModeResp();
                    mSMsgAVIoctrlGetVideoModeResp.mode = bytes[4];
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlGetVideoModeResp);
                    Logger.d(TAG, "video model:" + mSMsgAVIoctrlGetVideoModeResp.mode);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_GETMOTIONDETECT_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlGetMotionDetectResp == null)
                        mSMsgAVIoctrlGetMotionDetectResp = mAVIOCTRLDEFs.new SMsgAVIoctrlGetMotionDetectResp();
                    mSMsgAVIoctrlGetMotionDetectResp.sensitivity = Packet.byteArrayToInt_Little(bytes, 4);
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlGetMotionDetectResp);
                    Logger.d(TAG, "motion detect:" + mSMsgAVIoctrlGetMotionDetectResp.sensitivity);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SETMOTIONDETECT_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlSetMotionDetectResp == null)
                        mSMsgAVIoctrlSetMotionDetectResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetMotionDetectResp();
                    mSMsgAVIoctrlSetMotionDetectResp.result = bytes[0];
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlSetMotionDetectResp);
                    Logger.d(TAG, "set motion detect:" + mSMsgAVIoctrlSetMotionDetectResp.result);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SET_VIDEOMODE_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlSetVideoModeResp == null)
                        mSMsgAVIoctrlSetVideoModeResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetVideoModeResp();
                    mSMsgAVIoctrlSetVideoModeResp.result = bytes[4];
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlSetVideoModeResp);
                    Logger.d(TAG, "set video modle" + mSMsgAVIoctrlSetVideoModeResp.result);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SETRECORD_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlSetRecordResp == null)
                        mSMsgAVIoctrlSetRecordResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetRecordResp();
                    mSMsgAVIoctrlSetRecordResp.result = bytes[0];
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlSetRecordResp);
                    Logger.d(TAG, "set record " + mSMsgAVIoctrlSetRecordResp.result);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_GETRECORD_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlGetRecordResp == null)
                        mSMsgAVIoctrlGetRecordResp = mAVIOCTRLDEFs.new SMsgAVIoctrlGetRecordResp();
                    mSMsgAVIoctrlGetRecordResp.recordType = Packet.byteArrayToInt_Little(bytes, 4);
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlGetRecordResp);
                    Logger.d(TAG, "get recode:" + mSMsgAVIoctrlGetRecordResp.recordType);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_EVENT_REPORT: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.SMsgAVIoctrlEvent eventReport = mAVIOCTRLDEFs.new SMsgAVIoctrlEvent();
                    eventReport.stTime = new AVIOCTRLDEFs.STimeDay(Arrays.copyOfRange(bytes, 0, 8));
                    eventReport.channel = Packet.byteArrayToInt_Little(bytes, 8);
                    eventReport.event = Packet.byteArrayToInt_Little(bytes, 12);
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlSetRecordResp);
                    Logger.d(TAG, "event resp:" + eventReport.toString());
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_GET_ENVIRONMENT_RESP: {
                    if (mSMsgAVIoctrlGetEnvironmentResp == null) {
                        mSMsgAVIoctrlGetEnvironmentResp = mAVIOCTRLDEFs.new SMsgAVIoctrlGetEnvironmentResp();
                        mSMsgAVIoctrlGetEnvironmentResp.mode = ((byte[]) msg.obj)[4];
                    }
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlGetEnvironmentResp);
                    Logger.d(TAG, "event resp:===" + mSMsgAVIoctrlGetEnvironmentResp.mode);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SET_ENVIRONMENT_RESP: {
                	 byte[] bytes = (byte[]) msg.obj;
                     if (mSMsgAVIoctrlSetEnvironmentResp == null)
                    	 mSMsgAVIoctrlSetEnvironmentResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetEnvironmentResp();
                     mSMsgAVIoctrlSetEnvironmentResp.result = bytes[4];
                     setChanged();
                     notifyObservers(mSMsgAVIoctrlSetEnvironmentResp);
                     Logger.d(TAG, "set environment modle" + mSMsgAVIoctrlSetEnvironmentResp.result);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_GETSTREAMCTRL_RESP: {
                	if(mSMsgAVIoctrlGetStreamCtrlResp == null){
                		mSMsgAVIoctrlGetStreamCtrlResp  = mAVIOCTRLDEFs. new SMsgAVIoctrlGetStreamCtrlResp();
                		mSMsgAVIoctrlGetStreamCtrlResp.quality = ((byte[])msg.obj)[4];
                    }
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlGetStreamCtrlResp);
                    Logger.d(TAG, "quility resp:" + mSMsgAVIoctrlGetStreamCtrlResp.quality);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_LISTWIFIAP_RESP: {
                    if (mGetListWifiDone)
                        return;
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlListWifiApResp == null)
                        mSMsgAVIoctrlListWifiApResp = mAVIOCTRLDEFs.new SMsgAVIoctrlListWifiApResp();
                    mSMsgAVIoctrlListWifiApResp.number = bytes[0];
                    mSMsgAVIoctrlListWifiApResp.stWifiAps = new AVIOCTRLDEFs.SWifiAp[mSMsgAVIoctrlListWifiApResp.number];
                    for (int count = 0; count < mSMsgAVIoctrlListWifiApResp.number; count++) {
                        AVIOCTRLDEFs.SWifiAp sWifiAp = new AVIOCTRLDEFs.SWifiAp();
                        sWifiAp.ssid = Arrays.copyOfRange(bytes, 4 + count * 36, 36 + count * 36);
                        sWifiAp.mode = bytes[36 + count * 36];
                        sWifiAp.enctype = bytes[37 + count * 36];
                        sWifiAp.signal = bytes[38 + count * 36];
                        sWifiAp.status = bytes[39 + count * 36];
                        mSMsgAVIoctrlListWifiApResp.stWifiAps[count] = sWifiAp;
                    }
                    mGetListWifiDone = true;
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlListWifiApResp);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SETWIFI_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.SMsgAVIoctrlSetWifiResp wifiApResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetWifiResp();
                }
                break;
                case AVIOCTRLDEFs.ACCESS_OTA_FILE_CONFIG_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_FILE_CONFIG_RESP_CLASS respClass = new AVIOCTRLDEFs.ACCESS_OTA_FILE_CONFIG_RESP_CLASS();
                    respClass.result = bytes[0];
                    setChanged();
                    notifyObservers(respClass);
                }
                break;
                case AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_CHECK_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_CHECK_RESP_CLASS respClass = new AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_CHECK_RESP_CLASS();
                    respClass.result = bytes[0];
                    setChanged();
                    notifyObservers(respClass);
                }
                break;
                case AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_RESP_CLASS respClass = new AVIOCTRLDEFs.ACCESS_OTA_DEVICE_UPDATE_RESP_CLASS();
                    respClass.result = bytes[0];
                    setChanged();
                    notifyObservers(respClass);
                }
                break;
                case AVIOCTRLDEFs.ACCESS_OTA_FILE_DOWNLOAD_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_FILE_DOWNLOAD_RESP_CLASS respClass = new AVIOCTRLDEFs.ACCESS_OTA_FILE_DOWNLOAD_RESP_CLASS();
                    respClass.result = bytes[0];
                    setChanged();
                    notifyObservers(respClass);
                }
                break;
                case AVIOCTRLDEFs.ACCESS_OTA_FILE_OK_CHECK_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_FILE_OK_CHECK_RESP_CLASS respClass = new AVIOCTRLDEFs.ACCESS_OTA_FILE_OK_CHECK_RESP_CLASS();
                    respClass.result = bytes[0];
                    setChanged();
                    notifyObservers(respClass);
                }
                break;
                case AVIOCTRLDEFs.ACCESS_GET_CONFIG_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    AVIOCTRLDEFs.ACCESS_OTA_DEVICE_SET_CONFIG_INFO info = new AVIOCTRLDEFs.ACCESS_OTA_DEVICE_SET_CONFIG_INFO();
                    info.detail = CommApis.ByteToString(bytes);
                    setChanged();
                    notifyObservers(info);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SETSTREAMCTRL_RESP: {
                    byte[] bytes = (byte[]) msg.obj;
                    if (mSMsgAVIoctrlSetStreamCtrlResp == null)
                        mSMsgAVIoctrlSetStreamCtrlResp = mAVIOCTRLDEFs.new SMsgAVIoctrlSetStreamCtrlResp();
                    mSMsgAVIoctrlSetStreamCtrlResp.result = Packet.byteArrayToInt_Little(bytes);
                    setChanged();
                    notifyObservers(mSMsgAVIoctrlSetStreamCtrlResp);
                    Logger.d(TAG, "set quility resp:" + mSMsgAVIoctrlSetStreamCtrlResp.result);
                }
                break;
                case AVIOCTRLDEFs.IOTYPE_USER_IPCAM_LISTEVENT_RESP: {
                    final byte[] bytes = (byte[]) msg.obj;
                    TaskHelper.exec(new Runnable() {
                        @Override
                        public void run() {
                            AVIOCTRLDEFs.SMsgAVIoctrlListEventResp resp = mAVIOCTRLDEFs.new SMsgAVIoctrlListEventResp();
                            resp.total = Packet.byteArrayToInt_Little(bytes, 4);
                            resp.index = bytes[8];
                            resp.endflag = bytes[9];
                            resp.count = bytes[10];
                            resp.stEvents = new ArrayList<AVIOCTRLDEFs.SAvEvent>();
                            int index = 0;
                            for (int count = 0; count < bytes.length - 1; count++) {
                                int indexBase = index++ * 12;  //每个为AvEvent为12个字节，那么每次都以12的倍数往上递增,base为每个event开始的标签位置
                                AVIOCTRLDEFs.SAvEvent sAvEvent = new AVIOCTRLDEFs.SAvEvent();
                                byte[] utcTimeBytes = Arrays.copyOfRange(bytes, 12 + indexBase, 20 + indexBase);
                                sAvEvent.utctime = new AVIOCTRLDEFs.STimeDay(utcTimeBytes);
                                sAvEvent.event = bytes[21+indexBase];
                                sAvEvent.status = bytes[22 + indexBase];
                                if (sAvEvent.utctime.year == 0) //说明bytes 后面并没有更多数据了，可以break了。
                                    break;
                                resp.stEvents.add(sAvEvent);
                                setChanged();
                                notifyObservers(resp);
                            }
                        }
                    });
                }
                break;
                case  AVIOCTRLDEFs.IOTYPE_USER_IPCAM_RECORD_PLAYCONTROL_RESP:{
                    final byte[] bytes = (byte[])msg.obj;
                    AVIOCTRLDEFs.SMsgAVIoctrlPlayRecordResp resp = mAVIOCTRLDEFs. new SMsgAVIoctrlPlayRecordResp();
                    resp.command = bytes[0];
                    resp.result = Packet.byteArrayToInt_Little(bytes,4);
                    setChanged();
                    notifyObservers(resp);
                }
                default:
                    break;
            }
        }
    };

    public synchronized void startReceiveTask(final int avIndex) {
        if (isStart)
            return;
        isStart = true;
        TaskHelper.exec(new Task() {
            @Override
            public void execute() throws Exception {
                int[] ioType = new int[1];
                byte[] ioCtrlBuf = new byte[MAX_BUF_SIZE];
                while (true) {
                    //FIXME:这样会导致一直创建Message对象吗？ 造成OOM？
                    int rc = AVAPIs.avRecvIOCtrl(avIndex, ioType, ioCtrlBuf, MAX_BUF_SIZE, 10000);
                    if (rc >= 0 || (ioType[0] == AVIOCTRLDEFs.IOTYPE_USER_IPCAM_LISTWIFIAP_RESP && !mGetListWifiDone)
                            || ioType[0] == AVIOCTRLDEFs.IOTYPE_USER_IPCAM_SETWIFI_RESP) {
                        Message msg = new Message();
                        msg.what = ioType[0];
                        byte[] resp = new byte[ioCtrlBuf.length];
                        System.arraycopy(ioCtrlBuf, 0, resp, 0, ioCtrlBuf.length);
                        msg.obj = resp;
                        mMainHanler.sendMessage(msg);
                        ioCtrlBuf = new byte[MAX_BUF_SIZE]; //因为这个时候ioCtrlBuf已经是脏数据了，要清空一下。JNI没有做这个
                    } /*else if (rc != AVAPIs.AV_ER_TIMEOUT) {
                        break;
                    }*/
                }
            }

            @Override
            public void callback(Exception e) {
            }
        });
    }
}
